package rpc_client

import (
	"errors"
	"http_server/src/common_util"
	"http_server/src/config"
	"http_server/src/utils"
	"net"
	"time"
)

// MethodBalancerMap 负载均衡器列表
var methodBalancerMap = map[string]config.Balancer{
	common_util.LoginMethod:               config.GetBalancer(config.BalancerRoundRobin, config.ServerList),
	common_util.TokenAuthenticationMethod: config.GetBalancer(config.BalancerRoundRobin, config.ServerList),
	common_util.UpdateUserMessageMethod:   config.GetBalancer(config.BalancerRoundRobin, config.ServerList),
	common_util.GetUserMessageMethod:      config.GetBalancer(config.BalancerRoundRobin, config.ServerList),
}

// getAddress 获取对应方法
func getAddress(methodName string) (string, error) {
	balancer, ok := methodBalancerMap[methodName]
	if !ok {
		return "", errors.New("暂无服务可用")
	}
	return balancer.Select()
}

func RPCCall(method string, params ...interface{}) (interface{}, error) {
	address, err := getAddress(method)
	if err != nil {
		return "", err
	}
	connPool, ok := config.ConnPoolMap[address]
	if !ok {
		return "", errors.New("连接池列表中不存在该连接池" + address)
	}
	conn, err := connPool.GetConn()
	if err != nil {
		return "", err
	}
	defer func(connPool *config.ConnPool, conn config.Conn) {
		err := connPool.ReleaseConn(&conn)
		if err != nil {
			common_util.ErrorLogger.Printf("将连接归还连接池出现失败")
		}
	}(connPool, *conn)
	client := &RPCClient{conn: conn.Conn}
	req := common_util.RPCRequest{
		Method: method,
		Params: params,
	}
	return client.Call(req)
}

// RPCClient 客户端结构
type RPCClient struct {
	conn net.Conn
}

// Call 调用远程方法
func (c *RPCClient) Call(req common_util.RPCRequest) (interface{}, error) {

	ch := make(chan common_util.RPCResponse, 1)

	go func() {
		var res common_util.RPCResponse
		// 发送请求
		encoder := utils.NewJSONEncoder(c.conn)
		if err := encoder.Encode(req); err != nil {
			res.Error = &common_util.RPCError{Message: "发送请求失败：" + err.Error()}
			ch <- res
			return
		}
		// 接收响应
		decoder := utils.NewJSONDecoder(c.conn)
		if err := decoder.Decode(&res); err != nil {
			res.Error = &common_util.RPCError{Message: "接收响应失败：" + err.Error()}
			ch <- res
			return
		}
		ch <- res
	}()
	select {
	case res := <-ch:
		// 检查是否有错误
		if res.Error != nil {
			return nil, errors.New(res.Error.Message)
		}
		return res.Result, nil
	case <-time.After(config.RpcTimeout):
		return nil, errors.New("远程调用出现超时")
	}
}
